/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
 
This file is part of Quake III Arena source code.
 
Quake III Arena source code is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
 
Quake III Arena source code is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.
 
You should have received a copy of the GNU General Public License
along with Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
===========================================================================
*/
//
/*
=============================================================================
 
START SERVER MENU *****
 
=============================================================================
*/


#include "ui_local.h"


#define GAMESERVER_BACK0		"menu/art/back_0"
#define GAMESERVER_BACK1		"menu/art/back_1"
#define GAMESERVER_NEXT0		"menu/art/next_0"
#define GAMESERVER_NEXT1		"menu/art/next_1"
#define GAMESERVER_FRAMEL		"menu/art/frame2_l"
#define GAMESERVER_FRAMER		"menu/art/frame1_r"
#define GAMESERVER_SELECT		"menu/art/maps_select"
#define GAMESERVER_SELECTED		"menu/art/maps_selected"
#define GAMESERVER_FIGHT0		"menu/art/fight_0"
#define GAMESERVER_FIGHT1		"menu/art/fight_1"
#define GAMESERVER_UNKNOWNMAP	"menu/art/unknownmap"
#define GAMESERVER_ARROWS		"menu/art/gs_arrows_0"
#define GAMESERVER_ARROWSL		"menu/art/gs_arrows_l"
#define GAMESERVER_ARROWSR		"menu/art/gs_arrows_r"

#define MAX_MAPROWS		2
#define MAX_MAPCOLS		2
#define MAX_MAPSPERPAGE	4

#define	MAX_SERVERSTEXT	8192

#define MAX_SERVERMAPS	64
#define MAX_NAMELENGTH	16

#define ID_GAMETYPE				10
#define ID_PICTURES				11	// 12, 13, 14
#define ID_PREVPAGE				15
#define ID_NEXTPAGE				16
#define ID_STARTSERVERBACK		17
#define ID_STARTSERVERNEXT		18

typedef struct
{
    menuframework_s	menu;

    menutext_s		banner;
    menubitmap_s	framel;
    menubitmap_s	framer;

    menulist_s		gametype;
    menubitmap_s	mappics[MAX_MAPSPERPAGE];
    menubitmap_s	mapbuttons[MAX_MAPSPERPAGE];
    menubitmap_s	arrows;
    menubitmap_s	prevpage;
    menubitmap_s	nextpage;
    menubitmap_s	back;
    menubitmap_s	next;

    menutext_s		mapname;
    menubitmap_s	item_null;

    qboolean		multiplayer;
    int				currentmap;
    int				nummaps;
    int				page;
    int				maxpages;
    char			maplist[MAX_SERVERMAPS][MAX_NAMELENGTH];
    int				mapGamebits[MAX_SERVERMAPS];
}
startserver_t;

static startserver_t s_startserver;

static const char *gametype_items[] =
    {
        "Free For All",
        "Team Deathmatch",
        "Tournament",
        "Capture the Flag",
        0
    };

static int gametype_remap[] = {GT_FFA, GT_TEAM, GT_TOURNAMENT, GT_CTF};
static int gametype_remap2[] = {0, 2, 0, 1, 3};

// use ui_servers2.c definition
extern const char* punkbuster_items[];

static void UI_ServerOptionsMenu( qboolean multiplayer );


/*
=================
GametypeBits
=================
*/
static int GametypeBits( char *string )
{
    int		bits;
    char	*p;
    char	*token;

    bits = 0;
    p = string;
    while( 1 )
    {
        token = COM_ParseExt( &p, qfalse );
        if( token[0] == 0 )
        {
            break;
        }

        if( Q_stricmp( token, "ffa" ) == 0 )
        {
            bits |= 1 << GT_FFA;
            continue;
        }

        if( Q_stricmp( token, "tourney" ) == 0 )
        {
            bits |= 1 << GT_TOURNAMENT;
            continue;
        }

        if( Q_stricmp( token, "single" ) == 0 )
        {
            bits |= 1 << GT_SINGLE_PLAYER;
            continue;
        }

        if( Q_stricmp( token, "team" ) == 0 )
        {
            bits |= 1 << GT_TEAM;
            continue;
        }

        if( Q_stricmp( token, "ctf" ) == 0 )
        {
            bits |= 1 << GT_CTF;
            continue;
        }
    }

    return bits;
}


/*
=================
StartServer_Update
=================
*/
static void StartServer_Update( void )
{
    int				i;
    int				top;
    static	char	picname[MAX_MAPSPERPAGE][64];

    top = s_startserver.page*MAX_MAPSPERPAGE;

    for (i=0; i<MAX_MAPSPERPAGE; i++)
    {
        if (top+i >= s_startserver.nummaps)
            break;

        Com_sprintf( picname[i], sizeof(picname[i]), "levelshots/%s", s_startserver.maplist[top+i] );

        s_startserver.mappics[i].generic.flags &= ~QMF_HIGHLIGHT;
        s_startserver.mappics[i].generic.name   = picname[i];
        s_startserver.mappics[i].shader         = 0;

        // reset
        s_startserver.mapbuttons[i].generic.flags |= QMF_PULSEIFFOCUS;
        s_startserver.mapbuttons[i].generic.flags &= ~QMF_INACTIVE;
    }

    for (; i<MAX_MAPSPERPAGE; i++)
    {
        s_startserver.mappics[i].generic.flags &= ~QMF_HIGHLIGHT;
        s_startserver.mappics[i].generic.name   = NULL;
        s_startserver.mappics[i].shader         = 0;

        // disable
        s_startserver.mapbuttons[i].generic.flags &= ~QMF_PULSEIFFOCUS;
        s_startserver.mapbuttons[i].generic.flags |= QMF_INACTIVE;
    }


    // no servers to start
    if( !s_startserver.nummaps )
    {
        s_startserver.next.generic.flags |= QMF_INACTIVE;

        // set the map name
        strcpy( s_startserver.mapname.string, "NO MAPS FOUND" );
    }
    else
    {
        // set the highlight
        s_startserver.next.generic.flags &= ~QMF_INACTIVE;
        i = s_startserver.currentmap - top;
        if ( i >=0 && i < MAX_MAPSPERPAGE )
        {
            s_startserver.mappics[i].generic.flags    |= QMF_HIGHLIGHT;
            s_startserver.mapbuttons[i].generic.flags &= ~QMF_PULSEIFFOCUS;
        }

        // set the map name
        strcpy( s_startserver.mapname.string, s_startserver.maplist[s_startserver.currentmap] );
    }

    Q_strupr( s_startserver.mapname.string );
}


/*
=================
StartServer_MapEvent
=================
*/
static void StartServer_MapEvent( void* ptr, int event )
{
    if( event != QM_ACTIVATED)
    {
        return;
    }

    s_startserver.currentmap = (s_startserver.page*MAX_MAPSPERPAGE) + (((menucommon_s*)ptr)->id - ID_PICTURES);
    StartServer_Update();
}


/*
=================
StartServer_GametypeEvent
=================
*/
static void StartServer_GametypeEvent( void* ptr, int event )
{
    int			i;
    int			count;
    int			gamebits;
    int			matchbits;
    const char	*info;

    if( event != QM_ACTIVATED)
    {
        return;
    }

    count = UI_GetNumArenas();
    s_startserver.nummaps = 0;
    matchbits = 1 << gametype_remap[s_startserver.gametype.curvalue];
    if( gametype_remap[s_startserver.gametype.curvalue] == GT_FFA )
    {
        matchbits |= ( 1 << GT_SINGLE_PLAYER );
    }
    for( i = 0; i < count; i++ )
    {
        info = UI_GetArenaInfoByNumber( i );

        gamebits = GametypeBits( Info_ValueForKey( info, "type") );
        if( !( gamebits & matchbits ) )
        {
            continue;
        }

        Q_strncpyz( s_startserver.maplist[s_startserver.nummaps], Info_ValueForKey( info, "map"), MAX_NAMELENGTH );
        Q_strupr( s_startserver.maplist[s_startserver.nummaps] );
        s_startserver.mapGamebits[s_startserver.nummaps] = gamebits;
        s_startserver.nummaps++;
    }
    s_startserver.maxpages = (s_startserver.nummaps + MAX_MAPSPERPAGE-1)/MAX_MAPSPERPAGE;
    s_startserver.page = 0;
    s_startserver.currentmap = 0;

    StartServer_Update();
}


/*
=================
StartServer_MenuEvent
=================
*/
static void StartServer_MenuEvent( void* ptr, int event )
{
    if( event != QM_ACTIVATED )
    {
        return;
    }

    switch( ((menucommon_s*)ptr)->id )
    {
    case ID_PREVPAGE:
        if( s_startserver.page > 0 )
        {
            s_startserver.page--;
            StartServer_Update();
        }
        break;

    case ID_NEXTPAGE:
        if( s_startserver.page < s_startserver.maxpages - 1 )
        {
            s_startserver.page++;
            StartServer_Update();
        }
        break;

    case ID_STARTSERVERNEXT:
        Cvar_SetValue( "g_gameType", gametype_remap[s_startserver.gametype.curvalue] );
        UI_ServerOptionsMenu( s_startserver.multiplayer );
        break;

    case ID_STARTSERVERBACK:
        UI_PopMenu();
        break;
    }
}


/*
===============
StartServer_LevelshotDraw
===============
*/
static void StartServer_LevelshotDraw( void *self )
{
    menubitmap_s	*b;
    int				x;
    int				y;
    int				w;
    int				h;
    int				n;

    b = (menubitmap_s *)self;

    if( !b->generic.name )
    {
        return;
    }

    if( b->generic.name && !b->shader )
    {
        b->shader = RE_RegisterShaderNoMip( b->generic.name );
        if( !b->shader && b->errorpic )
        {
            b->shader = RE_RegisterShaderNoMip( b->errorpic );
        }
    }

    if( b->focuspic && !b->focusshader )
    {
        b->focusshader = RE_RegisterShaderNoMip( b->focuspic );
    }

    x = b->generic.x;
    y = b->generic.y;
    w = b->width;
    h =	b->height;
    if( b->shader )
    {
        UI_DrawHandlePic( x, y, w, h, b->shader );
    }

    x = b->generic.x;
    y = b->generic.y + b->height;
    UI_FillRect( x, y, b->width, 28, colorBlack );

    x += b->width / 2;
    y += 4;
    n = s_startserver.page * MAX_MAPSPERPAGE + b->generic.id - ID_PICTURES;
    UI_DrawString( x, y, s_startserver.maplist[n], UI_CENTER|UI_SMALLFONT, color_orange );

    x = b->generic.x;
    y = b->generic.y;
    w = b->width;
    h =	b->height + 28;
    if( b->generic.flags & QMF_HIGHLIGHT )
    {
        UI_DrawHandlePic( x, y, w, h, b->focusshader );
    }
}


/*
=================
StartServer_MenuInit
=================
*/
static void StartServer_MenuInit( void )
{
    int	i;
    int	x;
    int	y;
    static char mapnamebuffer[64];

    // zero set all our globals
    memset( &s_startserver, 0 ,sizeof(startserver_t) );

    StartServer_Cache();

    s_startserver.menu.wrapAround = qtrue;
    s_startserver.menu.fullscreen = qtrue;

    s_startserver.banner.generic.type  = MTYPE_BTEXT;
    s_startserver.banner.generic.x	   = 320;
    s_startserver.banner.generic.y	   = 16;
    s_startserver.banner.string        = "GAME SERVER";
    s_startserver.banner.color         = color_white;
    s_startserver.banner.style         = UI_CENTER;

    s_startserver.framel.generic.type  = MTYPE_BITMAP;
    s_startserver.framel.generic.name  = GAMESERVER_FRAMEL;
    s_startserver.framel.generic.flags = QMF_INACTIVE;
    s_startserver.framel.generic.x	   = 0;
    s_startserver.framel.generic.y	   = 78;
    s_startserver.framel.width  	   = 256;
    s_startserver.framel.height  	   = 329;

    s_startserver.framer.generic.type  = MTYPE_BITMAP;
    s_startserver.framer.generic.name  = GAMESERVER_FRAMER;
    s_startserver.framer.generic.flags = QMF_INACTIVE;
    s_startserver.framer.generic.x	   = 376;
    s_startserver.framer.generic.y	   = 76;
    s_startserver.framer.width  	   = 256;
    s_startserver.framer.height  	   = 334;

    s_startserver.gametype.generic.type		= MTYPE_SPINCONTROL;
    s_startserver.gametype.generic.name		= "Game Type:";
    s_startserver.gametype.generic.flags	= QMF_PULSEIFFOCUS|QMF_SMALLFONT;
    s_startserver.gametype.generic.callback	= StartServer_GametypeEvent;
    s_startserver.gametype.generic.id		= ID_GAMETYPE;
    s_startserver.gametype.generic.x		= 320 - 24;
    s_startserver.gametype.generic.y		= 368;
    s_startserver.gametype.itemnames		= gametype_items;

    for (i=0; i<MAX_MAPSPERPAGE; i++)
    {
        x =	(i % MAX_MAPCOLS) * (128+8) + 188;
        y = (i / MAX_MAPROWS) * (128+8) + 96;

        s_startserver.mappics[i].generic.type   = MTYPE_BITMAP;
        s_startserver.mappics[i].generic.flags  = QMF_LEFT_JUSTIFY|QMF_INACTIVE;
        s_startserver.mappics[i].generic.x	    = x;
        s_startserver.mappics[i].generic.y	    = y;
        s_startserver.mappics[i].generic.id		= ID_PICTURES+i;
        s_startserver.mappics[i].width  		= 128;
        s_startserver.mappics[i].height  	    = 96;
        s_startserver.mappics[i].focuspic       = GAMESERVER_SELECTED;
        s_startserver.mappics[i].errorpic       = GAMESERVER_UNKNOWNMAP;
        s_startserver.mappics[i].generic.ownerdraw = StartServer_LevelshotDraw;

        s_startserver.mapbuttons[i].generic.type     = MTYPE_BITMAP;
        s_startserver.mapbuttons[i].generic.flags    = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_NODEFAULTINIT;
        s_startserver.mapbuttons[i].generic.id       = ID_PICTURES+i;
        s_startserver.mapbuttons[i].generic.callback = StartServer_MapEvent;
        s_startserver.mapbuttons[i].generic.x	     = x - 30;
        s_startserver.mapbuttons[i].generic.y	     = y - 32;
        s_startserver.mapbuttons[i].width  		     = 256;
        s_startserver.mapbuttons[i].height  	     = 248;
        s_startserver.mapbuttons[i].generic.left     = x;
        s_startserver.mapbuttons[i].generic.top  	 = y;
        s_startserver.mapbuttons[i].generic.right    = x + 128;
        s_startserver.mapbuttons[i].generic.bottom   = y + 128;
        s_startserver.mapbuttons[i].focuspic         = GAMESERVER_SELECT;
    }

    s_startserver.arrows.generic.type  = MTYPE_BITMAP;
    s_startserver.arrows.generic.name  = GAMESERVER_ARROWS;
    s_startserver.arrows.generic.flags = QMF_INACTIVE;
    s_startserver.arrows.generic.x	   = 260;
    s_startserver.arrows.generic.y	   = 400;
    s_startserver.arrows.width  	   = 128;
    s_startserver.arrows.height  	   = 32;

    s_startserver.prevpage.generic.type	    = MTYPE_BITMAP;
    s_startserver.prevpage.generic.flags    = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
    s_startserver.prevpage.generic.callback = StartServer_MenuEvent;
    s_startserver.prevpage.generic.id	    = ID_PREVPAGE;
    s_startserver.prevpage.generic.x		= 260;
    s_startserver.prevpage.generic.y		= 400;
    s_startserver.prevpage.width  		    = 64;
    s_startserver.prevpage.height  		    = 32;
    s_startserver.prevpage.focuspic         = GAMESERVER_ARROWSL;

    s_startserver.nextpage.generic.type	    = MTYPE_BITMAP;
    s_startserver.nextpage.generic.flags    = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
    s_startserver.nextpage.generic.callback = StartServer_MenuEvent;
    s_startserver.nextpage.generic.id	    = ID_NEXTPAGE;
    s_startserver.nextpage.generic.x		= 321;
    s_startserver.nextpage.generic.y		= 400;
    s_startserver.nextpage.width  		    = 64;
    s_startserver.nextpage.height  		    = 32;
    s_startserver.nextpage.focuspic         = GAMESERVER_ARROWSR;

    s_startserver.mapname.generic.type  = MTYPE_PTEXT;
    s_startserver.mapname.generic.flags = QMF_CENTER_JUSTIFY|QMF_INACTIVE;
    s_startserver.mapname.generic.x	    = 320;
    s_startserver.mapname.generic.y	    = 440;
    s_startserver.mapname.string        = mapnamebuffer;
    s_startserver.mapname.style         = UI_CENTER|UI_BIGFONT;
    s_startserver.mapname.color         = text_color_normal;

    s_startserver.back.generic.type	    = MTYPE_BITMAP;
    s_startserver.back.generic.name     = GAMESERVER_BACK0;
    s_startserver.back.generic.flags    = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
    s_startserver.back.generic.callback = StartServer_MenuEvent;
    s_startserver.back.generic.id	    = ID_STARTSERVERBACK;
    s_startserver.back.generic.x		= 0;
    s_startserver.back.generic.y		= 480-64;
    s_startserver.back.width  		    = 128;
    s_startserver.back.height  		    = 64;
    s_startserver.back.focuspic         = GAMESERVER_BACK1;

    s_startserver.next.generic.type	    = MTYPE_BITMAP;
    s_startserver.next.generic.name     = GAMESERVER_NEXT0;
    s_startserver.next.generic.flags    = QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS;
    s_startserver.next.generic.callback = StartServer_MenuEvent;
    s_startserver.next.generic.id	    = ID_STARTSERVERNEXT;
    s_startserver.next.generic.x		= 640;
    s_startserver.next.generic.y		= 480-64;
    s_startserver.next.width  		    = 128;
    s_startserver.next.height  		    = 64;
    s_startserver.next.focuspic         = GAMESERVER_NEXT1;

    s_startserver.item_null.generic.type	= MTYPE_BITMAP;
    s_startserver.item_null.generic.flags	= QMF_LEFT_JUSTIFY|QMF_MOUSEONLY|QMF_SILENT;
    s_startserver.item_null.generic.x		= 0;
    s_startserver.item_null.generic.y		= 0;
    s_startserver.item_null.width			= 640;
    s_startserver.item_null.height			= 480;

    Menu_AddItem( &s_startserver.menu, &s_startserver.banner );
    Menu_AddItem( &s_startserver.menu, &s_startserver.framel );
    Menu_AddItem( &s_startserver.menu, &s_startserver.framer );

    Menu_AddItem( &s_startserver.menu, &s_startserver.gametype );
    for (i=0; i<MAX_MAPSPERPAGE; i++)
    {
        Menu_AddItem( &s_startserver.menu, &s_startserver.mappics[i] );
        Menu_AddItem( &s_startserver.menu, &s_startserver.mapbuttons[i] );
    }

    Menu_AddItem( &s_startserver.menu, &s_startserver.arrows );
    Menu_AddItem( &s_startserver.menu, &s_startserver.prevpage );
    Menu_AddItem( &s_startserver.menu, &s_startserver.nextpage );
    Menu_AddItem( &s_startserver.menu, &s_startserver.back );
    Menu_AddItem( &s_startserver.menu, &s_startserver.next );
    Menu_AddItem( &s_startserver.menu, &s_startserver.mapname );
    Menu_AddItem( &s_startserver.menu, &s_startserver.item_null );

    StartServer_GametypeEvent( NULL, QM_ACTIVATED );
}


/*
=================
StartServer_Cache
=================
*/
void StartServer_Cache( void )
{
    int				i;
    const char		*info;
    qboolean		precache;
    char			picname[64];

    RE_RegisterShaderNoMip( GAMESERVER_BACK0 );
    RE_RegisterShaderNoMip( GAMESERVER_BACK1 );
    RE_RegisterShaderNoMip( GAMESERVER_NEXT0 );
    RE_RegisterShaderNoMip( GAMESERVER_NEXT1 );
    RE_RegisterShaderNoMip( GAMESERVER_FRAMEL );
    RE_RegisterShaderNoMip( GAMESERVER_FRAMER );
    RE_RegisterShaderNoMip( GAMESERVER_SELECT );
    RE_RegisterShaderNoMip( GAMESERVER_SELECTED );
    RE_RegisterShaderNoMip( GAMESERVER_UNKNOWNMAP );
    RE_RegisterShaderNoMip( GAMESERVER_ARROWS );
    RE_RegisterShaderNoMip( GAMESERVER_ARROWSL );
    RE_RegisterShaderNoMip( GAMESERVER_ARROWSR );

    precache = Cvar_VariableValue("com_buildscript");

    s_startserver.nummaps = UI_GetNumArenas();

    for( i = 0; i < s_startserver.nummaps; i++ )
    {
        info = UI_GetArenaInfoByNumber( i );

        Q_strncpyz( s_startserver.maplist[i], Info_ValueForKey( info, "map"), MAX_NAMELENGTH );
        Q_strupr( s_startserver.maplist[i] );
        s_startserver.mapGamebits[i] = GametypeBits( Info_ValueForKey( info, "type") );

        if( precache )
        {
            Com_sprintf( picname, sizeof(picname), "levelshots/%s", s_startserver.maplist[i] );
            RE_RegisterShaderNoMip(picname);
        }
    }

    s_startserver.maxpages = (s_startserver.nummaps + MAX_MAPSPERPAGE-1)/MAX_MAPSPERPAGE;
}


/*
=================
UI_StartServerMenu
=================
*/
void UI_StartServerMenu( qboolean multiplayer )
{
    StartServer_MenuInit();
    s_startserver.multiplayer = multiplayer;
    UI_PushMenu( &s_startserver.menu );
}



/*
=============================================================================
 
SERVER OPTIONS MENU *****
 
=============================================================================
*/

#define ID_PLAYER_TYPE			20
#define ID_MAXCLIENTS			21
#define ID_DEDICATED			22
#define ID_GO					23
#define ID_BACK					24

#define PLAYER_SLOTS			12


typedef struct
{
    menuframework_s		menu;

    menutext_s			banner;

    menubitmap_s		mappic;
    menubitmap_s		picframe;

    menulist_s			dedicated;
    menufield_s			timelimit;
    menufield_s			fraglimit;
    menufield_s			flaglimit;
    menuradiobutton_s	friendlyfire;
    menufield_s			hostname;
    menuradiobutton_s	pure;
    menulist_s			botSkill;

    menutext_s			player0;
    menulist_s			playerType[PLAYER_SLOTS];
    menutext_s			playerName[PLAYER_SLOTS];
    menulist_s			playerTeam[PLAYER_SLOTS];

    menubitmap_s		go;
    menubitmap_s		next;
    menubitmap_s		back;

    qboolean			multiplayer;
    int					gametype;
    char				mapnamebuffer[32];
    char				playerNameBuffers[PLAYER_SLOTS][16];

    qboolean			newBot;
    int					newBotIndex;
    char				newBotName[16];

    menulist_s		punkbuster;
}
serveroptions_t;

static serveroptions_t s_serveroptions;

static const char *dedicated_list[] =
    {
        "No",
        "LAN",
        "Internet",
        0
    };

static const char *playerType_list[] =
    {
        "Open",
        "Bot",
        "----",
        0
    };

static const char *playerTeam_list[] =
    {
        "Blue",
        "Red",
        0
    };

static const char *botSkill_list[] =
    {
        "I Can Win",
        "Bring It On",
        "Hurt Me Plenty",
        "Hardcore",
        "Nightmare!",
        0
    };


/*
=================
BotAlreadySelected
=================
*/
static qboolean BotAlreadySelected( const char *checkName )
{
    int		n;

    for( n = 1; n < PLAYER_SLOTS; n++ )
    {
        if( s_serveroptions.playerType[n].curvalue != 1 )
        {
            continue;
        }
        if( (s_serveroptions.gametype >= GT_TEAM) &&
                (s_serveroptions.playerTeam[n].curvalue != s_serveroptions.playerTeam[s_serveroptions.newBotIndex].curvalue ) )
        {
            continue;
        }
        if( Q_stricmp( checkName, s_serveroptions.playerNameBuffers[n] ) == 0 )
        {
            return qtrue;
        }
    }

    return qfalse;
}


/*
=================
ServerOptions_Start
=================
*/
static void ServerOptions_Start( void )
{
    int		timelimit;
    int		fraglimit;
    int		maxclients;
    int		dedicated;
    int		friendlyfire;
    int		flaglimit;
    int		pure;
    int		skill;
    int		n;
    char	buf[64];


    timelimit	 = atoi( s_serveroptions.timelimit.field.buffer );
    fraglimit	 = atoi( s_serveroptions.fraglimit.field.buffer );
    flaglimit	 = atoi( s_serveroptions.flaglimit.field.buffer );
    dedicated	 = s_serveroptions.dedicated.curvalue;
    friendlyfire = s_serveroptions.friendlyfire.curvalue;
    pure		 = s_serveroptions.pure.curvalue;
    skill		 = s_serveroptions.botSkill.curvalue + 1;

    //set maxclients
    for( n = 0, maxclients = 0; n < PLAYER_SLOTS; n++ )
    {
        if( s_serveroptions.playerType[n].curvalue == 2 )
        {
            continue;
        }
        if( (s_serveroptions.playerType[n].curvalue == 1) && (s_serveroptions.playerNameBuffers[n][0] == 0) )
        {
            continue;
        }
        maxclients++;
    }

    switch( s_serveroptions.gametype )
    {
    case GT_FFA:
    default:
        Cvar_SetValue( "ui_ffa_fraglimit", fraglimit );
        Cvar_SetValue( "ui_ffa_timelimit", timelimit );
        break;

    case GT_TOURNAMENT:
        Cvar_SetValue( "ui_tourney_fraglimit", fraglimit );
        Cvar_SetValue( "ui_tourney_timelimit", timelimit );
        break;

    case GT_TEAM:
        Cvar_SetValue( "ui_team_fraglimit", fraglimit );
        Cvar_SetValue( "ui_team_timelimit", timelimit );
        Cvar_SetValue( "ui_team_friendlt", friendlyfire );
        break;

    case GT_CTF:
        Cvar_SetValue( "ui_ctf_fraglimit", fraglimit );
        Cvar_SetValue( "ui_ctf_timelimit", timelimit );
        Cvar_SetValue( "ui_ctf_friendlt", friendlyfire );
        break;
    }

    Cvar_SetValue( "sv_maxclients", Com_Clamp( 0, 12, maxclients ) );
    Cvar_SetValue( "dedicated", Com_Clamp( 0, 2, dedicated ) );
    Cvar_SetValue ("timelimit", Com_Clamp( 0, timelimit, timelimit ) );
    Cvar_SetValue ("fraglimit", Com_Clamp( 0, fraglimit, fraglimit ) );
    Cvar_SetValue ("capturelimit", Com_Clamp( 0, flaglimit, flaglimit ) );
    Cvar_SetValue( "g_friendlyfire", friendlyfire );
    Cvar_SetValue( "sv_pure", pure );
    Cvar_Set("sv_hostname", s_serveroptions.hostname.field.buffer );

    Cvar_SetValue( "sv_punkbuster", s_serveroptions.punkbuster.curvalue );

    // the wait commands will allow the dedicated to take effect
    Cbuf_ExecuteText( EXEC_APPEND, va( "wait ; wait ; map %s\n", s_startserver.maplist[s_startserver.currentmap] ) );

    // add bots
    Cbuf_ExecuteText( EXEC_APPEND, "wait 3\n" );
    for( n = 1; n < PLAYER_SLOTS; n++ )
    {
        if( s_serveroptions.playerType[n].curvalue != 1 )
        {
            continue;
        }
        if( s_serveroptions.playerNameBuffers[n][0] == 0 )
        {
            continue;
        }
        if( s_serveroptions.playerNameBuffers[n][0] == '-' )
        {
            continue;
        }
        if( s_serveroptions.gametype >= GT_TEAM )
        {
            Com_sprintf( buf, sizeof(buf), "addbot %s %i %s\n", s_serveroptions.playerNameBuffers[n], skill,
                         playerTeam_list[s_serveroptions.playerTeam[n].curvalue] );
        }
        else
        {
            Com_sprintf( buf, sizeof(buf), "addbot %s %i\n", s_serveroptions.playerNameBuffers[n], skill );
        }
        Cbuf_ExecuteText( EXEC_APPEND, buf );
    }

    // set player's team
    if( dedicated == 0 && s_serveroptions.gametype >= GT_TEAM )
    {
        Cbuf_ExecuteText( EXEC_APPEND, va( "wait 5; team %s\n", playerTeam_list[s_serveroptions.playerTeam[0].curvalue] ) );
    }
}


/*
=================
ServerOptions_InitPlayerItems
=================
*/
static void ServerOptions_InitPlayerItems( void )
{
    int		n;
    int		v;

    // init types
    if( s_serveroptions.multiplayer )
    {
        v = 0;	// open
    }
    else
    {
        v = 1;	// bot
    }

    for( n = 0; n < PLAYER_SLOTS; n++ )
    {
        s_serveroptions.playerType[n].curvalue = v;
    }

    if( s_serveroptions.multiplayer && (s_serveroptions.gametype < GT_TEAM) )
    {
        for( n = 8; n < PLAYER_SLOTS; n++ )
        {
            s_serveroptions.playerType[n].curvalue = 2;
        }
    }

    // if not a dedicated server, first slot is reserved for the human on the server
    if( s_serveroptions.dedicated.curvalue == 0 )
    {
        // human
        s_serveroptions.playerType[0].generic.flags |= QMF_INACTIVE;
        s_serveroptions.playerType[0].curvalue = 0;
        Cvar_VariableStringBuffer( "name", s_serveroptions.playerNameBuffers[0], sizeof(s_serveroptions.playerNameBuffers[0]) );
        Q_CleanStr( s_serveroptions.playerNameBuffers[0] );
    }

    // init teams
    if( s_serveroptions.gametype >= GT_TEAM )
    {
        for( n = 0; n < (PLAYER_SLOTS / 2); n++ )
        {
            s_serveroptions.playerTeam[n].curvalue = 0;
        }
        for( ; n < PLAYER_SLOTS; n++ )
        {
            s_serveroptions.playerTeam[n].curvalue = 1;
        }
    }
    else
    {
        for( n = 0; n < PLAYER_SLOTS; n++ )
        {
            s_serveroptions.playerTeam[n].generic.flags |= (QMF_INACTIVE|QMF_HIDDEN);
        }
    }
}


/*
=================
ServerOptions_SetPlayerItems
=================
*/
static void ServerOptions_SetPlayerItems( void )
{
    int		start;
    int		n;

    // types
//	for( n = 0; n < PLAYER_SLOTS; n++ ) {
//		if( (!s_serveroptions.multiplayer) && (n > 0) && (s_serveroptions.playerType[n].curvalue == 0) ) {
//			s_serveroptions.playerType[n].curvalue = 1;
//		}
//	}

    // names
    if( s_serveroptions.dedicated.curvalue == 0 )
    {
        s_serveroptions.player0.string = "Human";
        s_serveroptions.playerName[0].generic.flags &= ~QMF_HIDDEN;

        start = 1;
    }
    else
    {
        s_serveroptions.player0.string = "Open";
        start = 0;
    }
    for( n = start; n < PLAYER_SLOTS; n++ )
    {
        if( s_serveroptions.playerType[n].curvalue == 1 )
        {
            s_serveroptions.playerName[n].generic.flags &= ~(QMF_INACTIVE|QMF_HIDDEN);
        }
        else
        {
            s_serveroptions.playerName[n].generic.flags |= (QMF_INACTIVE|QMF_HIDDEN);
        }
    }

    // teams
    if( s_serveroptions.gametype < GT_TEAM )
    {
        return;
    }
    for( n = start; n < PLAYER_SLOTS; n++ )
    {
        if( s_serveroptions.playerType[n].curvalue == 2 )
        {
            s_serveroptions.playerTeam[n].generic.flags |= (QMF_INACTIVE|QMF_HIDDEN);
        }
        else
        {
            s_serveroptions.playerTeam[n].generic.flags &= ~(QMF_INACTIVE|QMF_HIDDEN);
        }
    }
}


/*
=================
ServerOptions_Event
=================
*/
static void ServerOptions_Event( void* ptr, int event )
{
    switch( ((menucommon_s*)ptr)->id )
    {

        //if( event != QM_ACTIVATED && event != QM_LOSTFOCUS) {
        //	return;
        //}
    case ID_PLAYER_TYPE:
        if( event != QM_ACTIVATED )
        {
            break;
        }
        ServerOptions_SetPlayerItems();
        break;

    case ID_MAXCLIENTS:
    case ID_DEDICATED:
        ServerOptions_SetPlayerItems();
        break;
    case ID_GO:
        if( event != QM_ACTIVATED )
        {
            break;
        }
        ServerOptions_Start();
        break;

    case ID_STARTSERVERNEXT:
        if( event != QM_ACTIVATED )
        {
            break;
        }
        break;
    case ID_BACK:
        if( event != QM_ACTIVATED )
        {
            break;
        }
        UI_PopMenu();
        break;
    }
}


static void ServerOptions_PlayerNameEvent( void* ptr, int event )
{
    int		n;

    if( event != QM_ACTIVATED )
    {
        return;
    }
    n = ((menutext_s*)ptr)->generic.id;
    s_serveroptions.newBotIndex = n;
    UI_BotSelectMenu( s_serveroptions.playerNameBuffers[n] );
}


/*
=================
ServerOptions_StatusBar
=================
*/
static void ServerOptions_StatusBar( void* ptr )
{
    switch( ((menucommon_s*)ptr)->id )
    {
    default:
        UI_DrawString( 320, 440, "0 = NO LIMIT", UI_CENTER|UI_SMALLFONT, colorWhite );
        break;
    }
}


/*
===============
ServerOptions_LevelshotDraw
===============
*/
static void ServerOptions_LevelshotDraw( void *self )
{
    menubitmap_s	*b;
    int				x;
    int				y;

    // strange place for this, but it works
    if( s_serveroptions.newBot )
    {
        Q_strncpyz( s_serveroptions.playerNameBuffers[s_serveroptions.newBotIndex], s_serveroptions.newBotName, 16 );
        s_serveroptions.newBot = qfalse;
    }

    b = (menubitmap_s *)self;

    Bitmap_Draw( b );

    x = b->generic.x;
    y = b->generic.y + b->height;
    UI_FillRect( x, y, b->width, 40, colorBlack );

    x += b->width / 2;
    y += 4;
    UI_DrawString( x, y, s_serveroptions.mapnamebuffer, UI_CENTER|UI_SMALLFONT, color_orange );

    y += SMALLCHAR_HEIGHT;
    UI_DrawString( x, y, gametype_items[gametype_remap2[s_serveroptions.gametype]], UI_CENTER|UI_SMALLFONT, color_orange );
}


static void ServerOptions_InitBotNames( void )
{
    int			count;
    int			n;
    const char	*arenaInfo;
    const char	*botInfo;
    char		*p;
    char		*bot;
    char		bots[MAX_INFO_STRING];

    if( s_serveroptions.gametype >= GT_TEAM )
    {
        Q_strncpyz( s_serveroptions.playerNameBuffers[1], "grunt", 16 );
        Q_strncpyz( s_serveroptions.playerNameBuffers[2], "major", 16 );
        if( s_serveroptions.gametype == GT_TEAM )
        {
            Q_strncpyz( s_serveroptions.playerNameBuffers[3], "visor", 16 );
        }
        else
        {
            s_serveroptions.playerType[3].curvalue = 2;
        }
        s_serveroptions.playerType[4].curvalue = 2;
        s_serveroptions.playerType[5].curvalue = 2;

        Q_strncpyz( s_serveroptions.playerNameBuffers[6], "sarge", 16 );
        Q_strncpyz( s_serveroptions.playerNameBuffers[7], "grunt", 16 );
        Q_strncpyz( s_serveroptions.playerNameBuffers[8], "major", 16 );
        if( s_serveroptions.gametype == GT_TEAM )
        {
            Q_strncpyz( s_serveroptions.playerNameBuffers[9], "visor", 16 );
        }
        else
        {
            s_serveroptions.playerType[9].curvalue = 2;
        }
        s_serveroptions.playerType[10].curvalue = 2;
        s_serveroptions.playerType[11].curvalue = 2;

        return;
    }

    count = 1;	// skip the first slot, reserved for a human

    // get info for this map
    arenaInfo = UI_GetArenaInfoByMap( s_serveroptions.mapnamebuffer );

    // get the bot info - we'll seed with them if any are listed
    Q_strncpyz( bots, Info_ValueForKey( arenaInfo, "bots" ), sizeof(bots) );
    p = &bots[0];
    while( *p && count < PLAYER_SLOTS )
    {
        //skip spaces
        while( *p && *p == ' ' )
        {
            p++;
        }
        if( !p )
        {
            break;
        }

        // mark start of bot name
        bot = p;

        // skip until space of null
        while( *p && *p != ' ' )
        {
            p++;
        }
        if( *p )
        {
            *p++ = 0;
        }

        botInfo = UI_GetBotInfoByName( bot );
        bot = Info_ValueForKey( botInfo, "name" );

        Q_strncpyz( s_serveroptions.playerNameBuffers[count], bot, sizeof(s_serveroptions.playerNameBuffers[count]) );
        count++;
    }

    // set the rest of the bot slots to "---"
    for( n = count; n < PLAYER_SLOTS; n++ )
    {
        strcpy( s_serveroptions.playerNameBuffers[n], "--------" );
    }

    // pad up to #8 as open slots
    for( ;count < 8; count++ )
    {
        s_serveroptions.playerType[count].curvalue = 0;
    }

    // close off the rest by default
    for( ;count < PLAYER_SLOTS; count++ )
    {
        if( s_serveroptions.playerType[count].curvalue == 1 )
        {
            s_serveroptions.playerType[count].curvalue = 2;
        }
    }
}


/*
=================
ServerOptions_SetMenuItems
=================
*/
static void ServerOptions_SetMenuItems( void )
{
    static char picname[64];

    switch( s_serveroptions.gametype )
    {
    case GT_FFA:
    default:
        Com_sprintf( s_serveroptions.fraglimit.field.buffer, 4, "%i", (int)Com_Clamp( 0, 999, Cvar_VariableValue( "ui_ffa_fraglimit" ) ) );
        Com_sprintf( s_serveroptions.timelimit.field.buffer, 4, "%i", (int)Com_Clamp( 0, 999, Cvar_VariableValue( "ui_ffa_timelimit" ) ) );
        break;

    case GT_TOURNAMENT:
        Com_sprintf( s_serveroptions.fraglimit.field.buffer, 4, "%i", (int)Com_Clamp( 0, 999, Cvar_VariableValue( "ui_tourney_fraglimit" ) ) );
        Com_sprintf( s_serveroptions.timelimit.field.buffer, 4, "%i", (int)Com_Clamp( 0, 999, Cvar_VariableValue( "ui_tourney_timelimit" ) ) );
        break;

    case GT_TEAM:
        Com_sprintf( s_serveroptions.fraglimit.field.buffer, 4, "%i", (int)Com_Clamp( 0, 999, Cvar_VariableValue( "ui_team_fraglimit" ) ) );
        Com_sprintf( s_serveroptions.timelimit.field.buffer, 4, "%i", (int)Com_Clamp( 0, 999, Cvar_VariableValue( "ui_team_timelimit" ) ) );
        s_serveroptions.friendlyfire.curvalue = (int)Com_Clamp( 0, 1, Cvar_VariableValue( "ui_team_friendly" ) );
        break;

    case GT_CTF:
        Com_sprintf( s_serveroptions.flaglimit.field.buffer, 4, "%i", (int)Com_Clamp( 0, 100, Cvar_VariableValue( "ui_ctf_capturelimit" ) ) );
        Com_sprintf( s_serveroptions.timelimit.field.buffer, 4, "%i", (int)Com_Clamp( 0, 999, Cvar_VariableValue( "ui_ctf_timelimit" ) ) );
        s_serveroptions.friendlyfire.curvalue = (int)Com_Clamp( 0, 1, Cvar_VariableValue( "ui_ctf_friendly" ) );
        break;
    }

    Q_strncpyz( s_serveroptions.hostname.field.buffer, UI_Cvar_VariableString( "sv_hostname" ), sizeof( s_serveroptions.hostname.field.buffer ) );
    s_serveroptions.pure.curvalue = Com_Clamp( 0, 1, Cvar_VariableValue( "sv_pure" ) );

    // set the map pic
    Com_sprintf( picname, 64, "levelshots/%s", s_startserver.maplist[s_startserver.currentmap] );
    s_serveroptions.mappic.generic.name = picname;

    // set the map name
    strcpy( s_serveroptions.mapnamebuffer, s_startserver.mapname.string );
    Q_strupr( s_serveroptions.mapnamebuffer );

    // get the player selections initialized
    ServerOptions_InitPlayerItems();
    ServerOptions_SetPlayerItems();

    // seed bot names
    ServerOptions_InitBotNames();
    ServerOptions_SetPlayerItems();
}

/*
=================
PlayerName_Draw
=================
*/
static void PlayerName_Draw( void *item )
{
    menutext_s	*s;
    float		*color;
    int			x, y;
    int			style;
    qboolean	focus;

    s = (menutext_s *)item;

    x = s->generic.x;
    y =	s->generic.y;

    style = UI_SMALLFONT;
    focus = (s->generic.parent->cursor == s->generic.menuPosition);

    if ( s->generic.flags & QMF_GRAYED )
        color = text_color_disabled;
    else if ( focus )
    {
        color = text_color_highlight;
        style |= UI_PULSE;
    }
    else if ( s->generic.flags & QMF_BLINK )
    {
        color = text_color_highlight;
        style |= UI_BLINK;
    }
    else
        color = text_color_normal;

    if ( focus )
    {
        // draw cursor
        UI_FillRect( s->generic.left, s->generic.top, s->generic.right-s->generic.left+1, s->generic.bottom-s->generic.top+1, listbar_color );
        UI_DrawChar( x, y, 13, UI_CENTER|UI_BLINK|UI_SMALLFONT, color);
    }

    UI_DrawString( x - SMALLCHAR_WIDTH, y, s->generic.name, style|UI_RIGHT, color );
    UI_DrawString( x + SMALLCHAR_WIDTH, y, s->string, style|UI_LEFT, color );
}


/*
=================
ServerOptions_MenuInit
=================
*/
#define OPTIONS_X	456

static void ServerOptions_MenuInit( qboolean multiplayer )
{
    int		y;
    int		n;

    memset( &s_serveroptions, 0 ,sizeof(serveroptions_t) );
    s_serveroptions.multiplayer = multiplayer;
    s_serveroptions.gametype = (int)Com_Clamp( 0, 5, Cvar_VariableValue( "g_gameType" ) );
    s_serveroptions.punkbuster.curvalue = Com_Clamp( 0, 1, Cvar_VariableValue( "sv_punkbuster" ) );

    ServerOptions_Cache();

    s_serveroptions.menu.wrapAround = qtrue;
    s_serveroptions.menu.fullscreen = qtrue;

    s_serveroptions.banner.generic.type			= MTYPE_BTEXT;
    s_serveroptions.banner.generic.x			= 320;
    s_serveroptions.banner.generic.y			= 16;
    s_serveroptions.banner.string  				= "GAME SERVER";
    s_serveroptions.banner.color  				= color_white;
    s_serveroptions.banner.style  				= UI_CENTER;

    s_serveroptions.mappic.generic.type			= MTYPE_BITMAP;
    s_serveroptions.mappic.generic.flags		= QMF_LEFT_JUSTIFY|QMF_INACTIVE;
    s_serveroptions.mappic.generic.x			= 352;
    s_serveroptions.mappic.generic.y			= 80;
    s_serveroptions.mappic.width				= 160;
    s_serveroptions.mappic.height				= 120;
    s_serveroptions.mappic.errorpic				= GAMESERVER_UNKNOWNMAP;
    s_serveroptions.mappic.generic.ownerdraw	= ServerOptions_LevelshotDraw;

    s_serveroptions.picframe.generic.type		= MTYPE_BITMAP;
    s_serveroptions.picframe.generic.flags		= QMF_LEFT_JUSTIFY|QMF_INACTIVE|QMF_HIGHLIGHT;
    s_serveroptions.picframe.generic.x			= 352 - 38;
    s_serveroptions.picframe.generic.y			= 80 - 40;
    s_serveroptions.picframe.width  			= 320;
    s_serveroptions.picframe.height  			= 320;
    s_serveroptions.picframe.focuspic			= GAMESERVER_SELECT;

    y = 272;
    if( s_serveroptions.gametype != GT_CTF )
    {
        s_serveroptions.fraglimit.generic.type       = MTYPE_FIELD;
        s_serveroptions.fraglimit.generic.name       = "Frag Limit:";
        s_serveroptions.fraglimit.generic.flags      = QMF_NUMBERSONLY|QMF_PULSEIFFOCUS|QMF_SMALLFONT;
        s_serveroptions.fraglimit.generic.x	         = OPTIONS_X;
        s_serveroptions.fraglimit.generic.y	         = y;
        s_serveroptions.fraglimit.generic.statusbar  = ServerOptions_StatusBar;
        s_serveroptions.fraglimit.field.widthInChars = 3;
        s_serveroptions.fraglimit.field.maxchars     = 3;
    }
    else
    {
        s_serveroptions.flaglimit.generic.type       = MTYPE_FIELD;
        s_serveroptions.flaglimit.generic.name       = "Capture Limit:";
        s_serveroptions.flaglimit.generic.flags      = QMF_NUMBERSONLY|QMF_PULSEIFFOCUS|QMF_SMALLFONT;
        s_serveroptions.flaglimit.generic.x	         = OPTIONS_X;
        s_serveroptions.flaglimit.generic.y	         = y;
        s_serveroptions.flaglimit.generic.statusbar  = ServerOptions_StatusBar;
        s_serveroptions.flaglimit.field.widthInChars = 3;
        s_serveroptions.flaglimit.field.maxchars     = 3;
    }

    y += BIGCHAR_HEIGHT+2;
    s_serveroptions.timelimit.generic.type       = MTYPE_FIELD;
    s_serveroptions.timelimit.generic.name       = "Time Limit:";
    s_serveroptions.timelimit.generic.flags      = QMF_NUMBERSONLY|QMF_PULSEIFFOCUS|QMF_SMALLFONT;
    s_serveroptions.timelimit.generic.x	         = OPTIONS_X;
    s_serveroptions.timelimit.generic.y	         = y;
    s_serveroptions.timelimit.generic.statusbar  = ServerOptions_StatusBar;
    s_serveroptions.timelimit.field.widthInChars = 3;
    s_serveroptions.timelimit.field.maxchars     = 3;

    if( s_serveroptions.gametype >= GT_TEAM )
    {
        y += BIGCHAR_HEIGHT+2;
        s_serveroptions.friendlyfire.generic.type     = MTYPE_RADIOBUTTON;
        s_serveroptions.friendlyfire.generic.flags    = QMF_PULSEIFFOCUS|QMF_SMALLFONT;
        s_serveroptions.friendlyfire.generic.x	      = OPTIONS_X;
        s_serveroptions.friendlyfire.generic.y	      = y;
        s_serveroptions.friendlyfire.generic.name	  = "Friendly Fire:";
    }

    y += BIGCHAR_HEIGHT+2;
    s_serveroptions.pure.generic.type			= MTYPE_RADIOBUTTON;
    s_serveroptions.pure.generic.flags			= QMF_PULSEIFFOCUS|QMF_SMALLFONT;
    s_serveroptions.pure.generic.x				= OPTIONS_X;
    s_serveroptions.pure.generic.y				= y;
    s_serveroptions.pure.generic.name			= "Pure Server:";

    if( s_serveroptions.multiplayer )
    {
        y += BIGCHAR_HEIGHT+2;
        s_serveroptions.dedicated.generic.type		= MTYPE_SPINCONTROL;
        s_serveroptions.dedicated.generic.id		= ID_DEDICATED;
        s_serveroptions.dedicated.generic.flags		= QMF_PULSEIFFOCUS|QMF_SMALLFONT;
        s_serveroptions.dedicated.generic.callback	= ServerOptions_Event;
        s_serveroptions.dedicated.generic.x			= OPTIONS_X;
        s_serveroptions.dedicated.generic.y			= y;
        s_serveroptions.dedicated.generic.name		= "Dedicated:";
        s_serveroptions.dedicated.itemnames			= dedicated_list;
    }

    if( s_serveroptions.multiplayer )
    {
        y += BIGCHAR_HEIGHT+2;
        s_serveroptions.hostname.generic.type       = MTYPE_FIELD;
        s_serveroptions.hostname.generic.name       = "Hostname:";
        s_serveroptions.hostname.generic.flags      = QMF_SMALLFONT;
        s_serveroptions.hostname.generic.x          = OPTIONS_X;
        s_serveroptions.hostname.generic.y	        = y;
        s_serveroptions.hostname.field.widthInChars = 18;
        s_serveroptions.hostname.field.maxchars     = 64;
    }

    y += BIGCHAR_HEIGHT+2;
    s_serveroptions.punkbuster.generic.type			= MTYPE_SPINCONTROL;
    s_serveroptions.punkbuster.generic.name			= "Punkbuster:";
    s_serveroptions.punkbuster.generic.flags			= QMF_PULSEIFFOCUS|QMF_SMALLFONT;
    s_serveroptions.punkbuster.generic.id			= 0;
    s_serveroptions.punkbuster.generic.x				= OPTIONS_X;
    s_serveroptions.punkbuster.generic.y				= y;
    s_serveroptions.punkbuster.itemnames				= punkbuster_items;

    y = 80;
    s_serveroptions.botSkill.generic.type			= MTYPE_SPINCONTROL;
    s_serveroptions.botSkill.generic.flags			= QMF_PULSEIFFOCUS|QMF_SMALLFONT;
    s_serveroptions.botSkill.generic.name			= "Bot Skill:  ";
    s_serveroptions.botSkill.generic.x				= 32 + (strlen(s_serveroptions.botSkill.generic.name) + 2 ) * SMALLCHAR_WIDTH;
    s_serveroptions.botSkill.generic.y				= y;
    s_serveroptions.botSkill.itemnames				= botSkill_list;
    s_serveroptions.botSkill.curvalue				= 1;

    y += ( 2 * SMALLCHAR_HEIGHT );
    s_serveroptions.player0.generic.type			= MTYPE_TEXT;
    s_serveroptions.player0.generic.flags			= QMF_SMALLFONT;
    s_serveroptions.player0.generic.x				= 32 + SMALLCHAR_WIDTH;
    s_serveroptions.player0.generic.y				= y;
    s_serveroptions.player0.color					= color_orange;
    s_serveroptions.player0.style					= UI_LEFT|UI_SMALLFONT;

    for( n = 0; n < PLAYER_SLOTS; n++ )
    {
        s_serveroptions.playerType[n].generic.type		= MTYPE_SPINCONTROL;
        s_serveroptions.playerType[n].generic.flags		= QMF_SMALLFONT;
        s_serveroptions.playerType[n].generic.id		= ID_PLAYER_TYPE;
        s_serveroptions.playerType[n].generic.callback	= ServerOptions_Event;
        s_serveroptions.playerType[n].generic.x			= 32;
        s_serveroptions.playerType[n].generic.y			= y;
        s_serveroptions.playerType[n].itemnames			= playerType_list;

        s_serveroptions.playerName[n].generic.type		= MTYPE_TEXT;
        s_serveroptions.playerName[n].generic.flags		= QMF_SMALLFONT;
        s_serveroptions.playerName[n].generic.x			= 96;
        s_serveroptions.playerName[n].generic.y			= y;
        s_serveroptions.playerName[n].generic.callback	= ServerOptions_PlayerNameEvent;
        s_serveroptions.playerName[n].generic.id		= n;
        s_serveroptions.playerName[n].generic.ownerdraw	= PlayerName_Draw;
        s_serveroptions.playerName[n].color				= color_orange;
        s_serveroptions.playerName[n].style				= UI_SMALLFONT;
        s_serveroptions.playerName[n].string			= s_serveroptions.playerNameBuffers[n];
        s_serveroptions.playerName[n].generic.top		= s_serveroptions.playerName[n].generic.y;
        s_serveroptions.playerName[n].generic.bottom	= s_serveroptions.playerName[n].generic.y + SMALLCHAR_HEIGHT;
        s_serveroptions.playerName[n].generic.left		= s_serveroptions.playerName[n].generic.x - SMALLCHAR_HEIGHT/ 2;
        s_serveroptions.playerName[n].generic.right		= s_serveroptions.playerName[n].generic.x + 16 * SMALLCHAR_WIDTH;

        s_serveroptions.playerTeam[n].generic.type		= MTYPE_SPINCONTROL;
        s_serveroptions.playerTeam[n].generic.flags		= QMF_SMALLFONT;
        s_serveroptions.playerTeam[n].generic.x			= 240;
        s_serveroptions.playerTeam[n].generic.y			= y;
        s_serveroptions.playerTeam[n].itemnames			= playerTeam_list;

        y += ( SMALLCHAR_HEIGHT + 4 );
    }

    s_serveroptions.back.generic.type	  = MTYPE_BITMAP;
    s_serveroptions.back.generic.name     = GAMESERVER_BACK0;
    s_serveroptions.back.generic.flags    = QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
    s_serveroptions.back.generic.callback = ServerOptions_Event;
    s_serveroptions.back.generic.id	      = ID_BACK;
    s_serveroptions.back.generic.x		  = 0;
    s_serveroptions.back.generic.y		  = 480-64;
    s_serveroptions.back.width  		  = 128;
    s_serveroptions.back.height  		  = 64;
    s_serveroptions.back.focuspic         = GAMESERVER_BACK1;

    s_serveroptions.next.generic.type	  = MTYPE_BITMAP;
    s_serveroptions.next.generic.name     = GAMESERVER_NEXT0;
    s_serveroptions.next.generic.flags    = QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS|QMF_INACTIVE|QMF_GRAYED|QMF_HIDDEN;
    s_serveroptions.next.generic.callback = ServerOptions_Event;
    s_serveroptions.next.generic.id	      = ID_STARTSERVERNEXT;
    s_serveroptions.next.generic.x		  = 640;
    s_serveroptions.next.generic.y		  = 480-64-72;
    s_serveroptions.next.generic.statusbar  = ServerOptions_StatusBar;
    s_serveroptions.next.width  		  = 128;
    s_serveroptions.next.height  		  = 64;
    s_serveroptions.next.focuspic         = GAMESERVER_NEXT1;

    s_serveroptions.go.generic.type	    = MTYPE_BITMAP;
    s_serveroptions.go.generic.name     = GAMESERVER_FIGHT0;
    s_serveroptions.go.generic.flags    = QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS;
    s_serveroptions.go.generic.callback = ServerOptions_Event;
    s_serveroptions.go.generic.id	    = ID_GO;
    s_serveroptions.go.generic.x		= 640;
    s_serveroptions.go.generic.y		= 480-64;
    s_serveroptions.go.width  		    = 128;
    s_serveroptions.go.height  		    = 64;
    s_serveroptions.go.focuspic         = GAMESERVER_FIGHT1;

    Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.banner );

    Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.mappic );
    Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.picframe );

    Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.botSkill );
    Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.player0 );
    for( n = 0; n < PLAYER_SLOTS; n++ )
    {
        if( n != 0 )
        {
            Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.playerType[n] );
        }
        Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.playerName[n] );
        if( s_serveroptions.gametype >= GT_TEAM )
        {
            Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.playerTeam[n] );
        }
    }

    if( s_serveroptions.gametype != GT_CTF )
    {
        Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.fraglimit );
    }
    else
    {
        Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.flaglimit );
    }
    Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.timelimit );
    if( s_serveroptions.gametype >= GT_TEAM )
    {
        Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.friendlyfire );
    }
    Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.pure );
    if( s_serveroptions.multiplayer )
    {
        Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.dedicated );
    }
    if( s_serveroptions.multiplayer )
    {
        Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.hostname );
    }

    Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.back );
    Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.next );
    Menu_AddItem( &s_serveroptions.menu, &s_serveroptions.go );

    Menu_AddItem( &s_serveroptions.menu, (void*) &s_serveroptions.punkbuster );

    ServerOptions_SetMenuItems();
}

/*
=================
ServerOptions_Cache
=================
*/
void ServerOptions_Cache( void )
{
    RE_RegisterShaderNoMip( GAMESERVER_BACK0 );
    RE_RegisterShaderNoMip( GAMESERVER_BACK1 );
    RE_RegisterShaderNoMip( GAMESERVER_FIGHT0 );
    RE_RegisterShaderNoMip( GAMESERVER_FIGHT1 );
    RE_RegisterShaderNoMip( GAMESERVER_SELECT );
    RE_RegisterShaderNoMip( GAMESERVER_UNKNOWNMAP );
}


/*
=================
UI_ServerOptionsMenu
=================
*/
static void UI_ServerOptionsMenu( qboolean multiplayer )
{
    ServerOptions_MenuInit( multiplayer );
    UI_PushMenu( &s_serveroptions.menu );
}



/*
=============================================================================
 
BOT SELECT MENU *****
 
=============================================================================
*/


#define BOTSELECT_BACK0			"menu/art/back_0"
#define BOTSELECT_BACK1			"menu/art/back_1"
#define BOTSELECT_ACCEPT0		"menu/art/accept_0"
#define BOTSELECT_ACCEPT1		"menu/art/accept_1"
#define BOTSELECT_SELECT		"menu/art/opponents_select"
#define BOTSELECT_SELECTED		"menu/art/opponents_selected"
#define BOTSELECT_ARROWS		"menu/art/gs_arrows_0"
#define BOTSELECT_ARROWSL		"menu/art/gs_arrows_l"
#define BOTSELECT_ARROWSR		"menu/art/gs_arrows_r"

#define PLAYERGRID_COLS			4
#define PLAYERGRID_ROWS			4
#define MAX_MODELSPERPAGE		(PLAYERGRID_ROWS * PLAYERGRID_COLS)


typedef struct
{
    menuframework_s	menu;

    menutext_s		banner;

    menubitmap_s	pics[MAX_MODELSPERPAGE];
    menubitmap_s	picbuttons[MAX_MODELSPERPAGE];
    menutext_s		picnames[MAX_MODELSPERPAGE];

    menubitmap_s	arrows;
    menubitmap_s	left;
    menubitmap_s	right;

    menubitmap_s	go;
    menubitmap_s	back;

    int				numBots;
    int				modelpage;
    int				numpages;
    int				selectedmodel;
    int				sortedBotNums[MAX_BOTS];
    char			boticons[MAX_MODELSPERPAGE][MAX_QPATH];
    char			botnames[MAX_MODELSPERPAGE][16];
}
botSelectInfo_t;

static botSelectInfo_t	botSelectInfo;


/*
=================
UI_BotSelectMenu_SortCompare
=================
*/
static int QDECL UI_BotSelectMenu_SortCompare( const void *arg1, const void *arg2 )
{
    int			num1, num2;
    const char	*info1, *info2;
    const char	*name1, *name2;

    num1 = *(int *)arg1;
    num2 = *(int *)arg2;

    info1 = UI_GetBotInfoByNumber( num1 );
    info2 = UI_GetBotInfoByNumber( num2 );

    name1 = Info_ValueForKey( info1, "name" );
    name2 = Info_ValueForKey( info2, "name" );

    return Q_stricmp( name1, name2 );
}


/*
=================
UI_BotSelectMenu_BuildList
=================
*/
static void UI_BotSelectMenu_BuildList( void )
{
    int		n;

    botSelectInfo.modelpage = 0;
    botSelectInfo.numBots = UI_GetNumBots();
    botSelectInfo.numpages = botSelectInfo.numBots / MAX_MODELSPERPAGE;
    if( botSelectInfo.numBots % MAX_MODELSPERPAGE )
    {
        botSelectInfo.numpages++;
    }

    // initialize the array
    for( n = 0; n < botSelectInfo.numBots; n++ )
    {
        botSelectInfo.sortedBotNums[n] = n;
    }

    // now sort it
    qsort( botSelectInfo.sortedBotNums, botSelectInfo.numBots, sizeof(botSelectInfo.sortedBotNums[0]), UI_BotSelectMenu_SortCompare );
}


/*
=================
ServerPlayerIcon
=================
*/
static void ServerPlayerIcon( const char *modelAndSkin, char *iconName, int iconNameMaxSize )
{
    char	*skin;
    char	model[MAX_QPATH];

    Q_strncpyz( model, modelAndSkin, sizeof(model));
    skin = Q_strrchr( model, '/' );
    if ( skin )
    {
        *skin++ = '\0';
    }
    else
    {
        skin = "default";
    }

    Com_sprintf(iconName, iconNameMaxSize, "models/players/%s/icon_%s.tga", model, skin );

    if( !RE_RegisterShaderNoMip( iconName ) && Q_stricmp( skin, "default" ) != 0 )
    {
        Com_sprintf(iconName, iconNameMaxSize, "models/players/%s/icon_default.tga", model );
    }
}


/*
=================
UI_BotSelectMenu_UpdateGrid
=================
*/
static void UI_BotSelectMenu_UpdateGrid( void )
{
    const char	*info;
    int			i;
    int			j;

    j = botSelectInfo.modelpage * MAX_MODELSPERPAGE;
    for( i = 0; i < (PLAYERGRID_ROWS * PLAYERGRID_COLS); i++, j++)
    {
        if( j < botSelectInfo.numBots )
        {
            info = UI_GetBotInfoByNumber( botSelectInfo.sortedBotNums[j] );
            ServerPlayerIcon( Info_ValueForKey( info, "model" ), botSelectInfo.boticons[i], MAX_QPATH );
            Q_strncpyz( botSelectInfo.botnames[i], Info_ValueForKey( info, "name" ), 16 );
            Q_CleanStr( botSelectInfo.botnames[i] );
            botSelectInfo.pics[i].generic.name = botSelectInfo.boticons[i];
            if( BotAlreadySelected( botSelectInfo.botnames[i] ) )
            {
                botSelectInfo.picnames[i].color = color_red;
            }
            else
            {
                botSelectInfo.picnames[i].color = color_orange;
            }
            botSelectInfo.picbuttons[i].generic.flags &= ~QMF_INACTIVE;
        }
        else
        {
            // dead slot
            botSelectInfo.pics[i].generic.name         = NULL;
            botSelectInfo.picbuttons[i].generic.flags |= QMF_INACTIVE;
            botSelectInfo.botnames[i][0] = 0;
        }

        botSelectInfo.pics[i].generic.flags       &= ~QMF_HIGHLIGHT;
        botSelectInfo.pics[i].shader               = 0;
        botSelectInfo.picbuttons[i].generic.flags |= QMF_PULSEIFFOCUS;
    }

    // set selected model
    i = botSelectInfo.selectedmodel % MAX_MODELSPERPAGE;
    botSelectInfo.pics[i].generic.flags |= QMF_HIGHLIGHT;
    botSelectInfo.picbuttons[i].generic.flags &= ~QMF_PULSEIFFOCUS;

    if( botSelectInfo.numpages > 1 )
    {
        if( botSelectInfo.modelpage > 0 )
        {
            botSelectInfo.left.generic.flags &= ~QMF_INACTIVE;
        }
        else
        {
            botSelectInfo.left.generic.flags |= QMF_INACTIVE;
        }

        if( botSelectInfo.modelpage < (botSelectInfo.numpages - 1) )
        {
            botSelectInfo.right.generic.flags &= ~QMF_INACTIVE;
        }
        else
        {
            botSelectInfo.right.generic.flags |= QMF_INACTIVE;
        }
    }
    else
    {
        // hide left/right markers
        botSelectInfo.left.generic.flags |= QMF_INACTIVE;
        botSelectInfo.right.generic.flags |= QMF_INACTIVE;
    }
}


/*
=================
UI_BotSelectMenu_Default
=================
*/
static void UI_BotSelectMenu_Default( char *bot )
{
    const char	*botInfo;
    const char	*test;
    int			n;
    int			i;

    for( n = 0; n < botSelectInfo.numBots; n++ )
    {
        botInfo = UI_GetBotInfoByNumber( n );
        test = Info_ValueForKey( botInfo, "name" );
        if( Q_stricmp( bot, test ) == 0 )
        {
            break;
        }
    }
    if( n == botSelectInfo.numBots )
    {
        botSelectInfo.selectedmodel = 0;
        return;
    }

    for( i = 0; i < botSelectInfo.numBots; i++ )
    {
        if( botSelectInfo.sortedBotNums[i] == n )
        {
            break;
        }
    }
    if( i == botSelectInfo.numBots )
    {
        botSelectInfo.selectedmodel = 0;
        return;
    }

    botSelectInfo.selectedmodel = i;
}


/*
=================
UI_BotSelectMenu_LeftEvent
=================
*/
static void UI_BotSelectMenu_LeftEvent( void* ptr, int event )
{
    if( event != QM_ACTIVATED )
    {
        return;
    }
    if( botSelectInfo.modelpage > 0 )
    {
        botSelectInfo.modelpage--;
        botSelectInfo.selectedmodel = botSelectInfo.modelpage * MAX_MODELSPERPAGE;
        UI_BotSelectMenu_UpdateGrid();
    }
}


/*
=================
UI_BotSelectMenu_RightEvent
=================
*/
static void UI_BotSelectMenu_RightEvent( void* ptr, int event )
{
    if( event != QM_ACTIVATED )
    {
        return;
    }
    if( botSelectInfo.modelpage < botSelectInfo.numpages - 1 )
    {
        botSelectInfo.modelpage++;
        botSelectInfo.selectedmodel = botSelectInfo.modelpage * MAX_MODELSPERPAGE;
        UI_BotSelectMenu_UpdateGrid();
    }
}


/*
=================
UI_BotSelectMenu_BotEvent
=================
*/
static void UI_BotSelectMenu_BotEvent( void* ptr, int event )
{
    int		i;

    if( event != QM_ACTIVATED )
    {
        return;
    }

    for( i = 0; i < (PLAYERGRID_ROWS * PLAYERGRID_COLS); i++ )
    {
        botSelectInfo.pics[i].generic.flags &= ~QMF_HIGHLIGHT;
        botSelectInfo.picbuttons[i].generic.flags |= QMF_PULSEIFFOCUS;
    }

    // set selected
    i = ((menucommon_s*)ptr)->id;
    botSelectInfo.pics[i].generic.flags |= QMF_HIGHLIGHT;
    botSelectInfo.picbuttons[i].generic.flags &= ~QMF_PULSEIFFOCUS;
    botSelectInfo.selectedmodel = botSelectInfo.modelpage * MAX_MODELSPERPAGE + i;
}


/*
=================
UI_BotSelectMenu_BackEvent
=================
*/
static void UI_BotSelectMenu_BackEvent( void* ptr, int event )
{
    if( event != QM_ACTIVATED )
    {
        return;
    }
    UI_PopMenu();
}


/*
=================
UI_BotSelectMenu_SelectEvent
=================
*/
static void UI_BotSelectMenu_SelectEvent( void* ptr, int event )
{
    if( event != QM_ACTIVATED )
    {
        return;
    }
    UI_PopMenu();

    s_serveroptions.newBot = qtrue;
    Q_strncpyz( s_serveroptions.newBotName, botSelectInfo.botnames[botSelectInfo.selectedmodel % MAX_MODELSPERPAGE], 16 );
}


/*
=================
UI_BotSelectMenu_Cache
=================
*/
void UI_BotSelectMenu_Cache( void )
{
    RE_RegisterShaderNoMip( BOTSELECT_BACK0 );
    RE_RegisterShaderNoMip( BOTSELECT_BACK1 );
    RE_RegisterShaderNoMip( BOTSELECT_ACCEPT0 );
    RE_RegisterShaderNoMip( BOTSELECT_ACCEPT1 );
    RE_RegisterShaderNoMip( BOTSELECT_SELECT );
    RE_RegisterShaderNoMip( BOTSELECT_SELECTED );
    RE_RegisterShaderNoMip( BOTSELECT_ARROWS );
    RE_RegisterShaderNoMip( BOTSELECT_ARROWSL );
    RE_RegisterShaderNoMip( BOTSELECT_ARROWSR );
}


static void UI_BotSelectMenu_Init( char *bot )
{
    int		i, j, k;
    int		x, y;

    memset( &botSelectInfo, 0 ,sizeof(botSelectInfo) );
    botSelectInfo.menu.wrapAround = qtrue;
    botSelectInfo.menu.fullscreen = qtrue;

    UI_BotSelectMenu_Cache();

    botSelectInfo.banner.generic.type	= MTYPE_BTEXT;
    botSelectInfo.banner.generic.x		= 320;
    botSelectInfo.banner.generic.y		= 16;
    botSelectInfo.banner.string			= "SELECT BOT";
    botSelectInfo.banner.color			= color_white;
    botSelectInfo.banner.style			= UI_CENTER;

    y =	80;
    for( i = 0, k = 0; i < PLAYERGRID_ROWS; i++)
    {
        x =	180;
        for( j = 0; j < PLAYERGRID_COLS; j++, k++ )
        {
            botSelectInfo.pics[k].generic.type				= MTYPE_BITMAP;
            botSelectInfo.pics[k].generic.flags				= QMF_LEFT_JUSTIFY|QMF_INACTIVE;
            botSelectInfo.pics[k].generic.x					= x;
            botSelectInfo.pics[k].generic.y					= y;
            botSelectInfo.pics[k].generic.name				= botSelectInfo.boticons[k];
            botSelectInfo.pics[k].width						= 64;
            botSelectInfo.pics[k].height					= 64;
            botSelectInfo.pics[k].focuspic					= BOTSELECT_SELECTED;
            botSelectInfo.pics[k].focuscolor				= colorRed;

            botSelectInfo.picbuttons[k].generic.type		= MTYPE_BITMAP;
            botSelectInfo.picbuttons[k].generic.flags		= QMF_LEFT_JUSTIFY|QMF_NODEFAULTINIT|QMF_PULSEIFFOCUS;
            botSelectInfo.picbuttons[k].generic.callback	= UI_BotSelectMenu_BotEvent;
            botSelectInfo.picbuttons[k].generic.id			= k;
            botSelectInfo.picbuttons[k].generic.x			= x - 16;
            botSelectInfo.picbuttons[k].generic.y			= y - 16;
            botSelectInfo.picbuttons[k].generic.left		= x;
            botSelectInfo.picbuttons[k].generic.top			= y;
            botSelectInfo.picbuttons[k].generic.right		= x + 64;
            botSelectInfo.picbuttons[k].generic.bottom		= y + 64;
            botSelectInfo.picbuttons[k].width				= 128;
            botSelectInfo.picbuttons[k].height				= 128;
            botSelectInfo.picbuttons[k].focuspic			= BOTSELECT_SELECT;
            botSelectInfo.picbuttons[k].focuscolor			= colorRed;

            botSelectInfo.picnames[k].generic.type			= MTYPE_TEXT;
            botSelectInfo.picnames[k].generic.flags			= QMF_SMALLFONT;
            botSelectInfo.picnames[k].generic.x				= x + 32;
            botSelectInfo.picnames[k].generic.y				= y + 64;
            botSelectInfo.picnames[k].string				= botSelectInfo.botnames[k];
            botSelectInfo.picnames[k].color					= color_orange;
            botSelectInfo.picnames[k].style					= UI_CENTER|UI_SMALLFONT;

            x += (64 + 6);
        }
        y += (64 + SMALLCHAR_HEIGHT + 6);
    }

    botSelectInfo.arrows.generic.type		= MTYPE_BITMAP;
    botSelectInfo.arrows.generic.name		= BOTSELECT_ARROWS;
    botSelectInfo.arrows.generic.flags		= QMF_INACTIVE;
    botSelectInfo.arrows.generic.x			= 260;
    botSelectInfo.arrows.generic.y			= 440;
    botSelectInfo.arrows.width				= 128;
    botSelectInfo.arrows.height				= 32;

    botSelectInfo.left.generic.type			= MTYPE_BITMAP;
    botSelectInfo.left.generic.flags		= QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
    botSelectInfo.left.generic.callback		= UI_BotSelectMenu_LeftEvent;
    botSelectInfo.left.generic.x			= 260;
    botSelectInfo.left.generic.y			= 440;
    botSelectInfo.left.width  				= 64;
    botSelectInfo.left.height  				= 32;
    botSelectInfo.left.focuspic				= BOTSELECT_ARROWSL;

    botSelectInfo.right.generic.type	    = MTYPE_BITMAP;
    botSelectInfo.right.generic.flags		= QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
    botSelectInfo.right.generic.callback	= UI_BotSelectMenu_RightEvent;
    botSelectInfo.right.generic.x			= 321;
    botSelectInfo.right.generic.y			= 440;
    botSelectInfo.right.width  				= 64;
    botSelectInfo.right.height  		    = 32;
    botSelectInfo.right.focuspic			= BOTSELECT_ARROWSR;

    botSelectInfo.back.generic.type		= MTYPE_BITMAP;
    botSelectInfo.back.generic.name		= BOTSELECT_BACK0;
    botSelectInfo.back.generic.flags	= QMF_LEFT_JUSTIFY|QMF_PULSEIFFOCUS;
    botSelectInfo.back.generic.callback	= UI_BotSelectMenu_BackEvent;
    botSelectInfo.back.generic.x		= 0;
    botSelectInfo.back.generic.y		= 480-64;
    botSelectInfo.back.width			= 128;
    botSelectInfo.back.height			= 64;
    botSelectInfo.back.focuspic			= BOTSELECT_BACK1;

    botSelectInfo.go.generic.type		= MTYPE_BITMAP;
    botSelectInfo.go.generic.name		= BOTSELECT_ACCEPT0;
    botSelectInfo.go.generic.flags		= QMF_RIGHT_JUSTIFY|QMF_PULSEIFFOCUS;
    botSelectInfo.go.generic.callback	= UI_BotSelectMenu_SelectEvent;
    botSelectInfo.go.generic.x			= 640;
    botSelectInfo.go.generic.y			= 480-64;
    botSelectInfo.go.width				= 128;
    botSelectInfo.go.height				= 64;
    botSelectInfo.go.focuspic			= BOTSELECT_ACCEPT1;

    Menu_AddItem( &botSelectInfo.menu, &botSelectInfo.banner );
    for( i = 0; i < MAX_MODELSPERPAGE; i++ )
    {
        Menu_AddItem( &botSelectInfo.menu,	&botSelectInfo.pics[i] );
        Menu_AddItem( &botSelectInfo.menu,	&botSelectInfo.picbuttons[i] );
        Menu_AddItem( &botSelectInfo.menu,	&botSelectInfo.picnames[i] );
    }
    Menu_AddItem( &botSelectInfo.menu, &botSelectInfo.arrows );
    Menu_AddItem( &botSelectInfo.menu, &botSelectInfo.left );
    Menu_AddItem( &botSelectInfo.menu, &botSelectInfo.right );
    Menu_AddItem( &botSelectInfo.menu, &botSelectInfo.back );
    Menu_AddItem( &botSelectInfo.menu, &botSelectInfo.go );

    UI_BotSelectMenu_BuildList();
    UI_BotSelectMenu_Default( bot );
    botSelectInfo.modelpage = botSelectInfo.selectedmodel / MAX_MODELSPERPAGE;
    UI_BotSelectMenu_UpdateGrid();
}


/*
=================
UI_BotSelectMenu
=================
*/
void UI_BotSelectMenu( char *bot )
{
    UI_BotSelectMenu_Init( bot );
    UI_PushMenu( &botSelectInfo.menu );
}
